package cn.iocoder.yudao.module.infra.service.face;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.infra.api.face.dto.FaceOperationRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.face.vo.FaceDetectBase64ReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.face.vo.FaceRegisterBase64ReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.face.vo.FaceSearchBase64ReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.face.vo.FaceSearchRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.face.vo.FaceDeleteReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.face.FaceConfigDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.face.FaceLogDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.face.FaceRecordDO;
import com.baidu.aip.face.AipFace;
import com.baidu.aip.face.MatchRequest;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 人脸识别 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class FaceServiceImpl implements FaceService {

    @Resource
    private FaceConfigService faceConfigService;
    
    @Resource
    private FaceRecordService faceRecordService;
    
    @Resource
    private FaceLogService faceLogService;

    /**
     * 获取百度AI客户端
     */
    private AipFace getAipFaceClient() {
        FaceConfigDO config = faceConfigService.getEnabledConfig();
        if (config == null) {
            throw exception(FACE_CONFIG_NOT_ENABLED);
        }
        return new AipFace(config.getAppId(), config.getApiKey(), config.getSecretKey());
    }

    @Override
    public Map<String, Object> registerFace(Long userId, MultipartFile faceImage, String groupId) {
        try {
            AipFace client = getAipFaceClient();
            
            // 转换图片为Base64
            byte[] imageBytes = faceImage.getBytes();
            String imageType = "BASE64";
            String image = java.util.Base64.getEncoder().encodeToString(imageBytes);
            
            // 调用百度API注册人脸
            HashMap<String, String> options = new HashMap<>();
            options.put("user_info", "user_" + userId);
            options.put("quality_control", "NORMAL");
            options.put("liveness_control", "LOW");
            
            org.json.JSONObject baiduResult = client.addUser(image, imageType, groupId, userId.toString(), options);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 记录日志
            createFaceLog(userId, "REGISTER", null, result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), null);
            
            if (result.getInt("error_code") == 0) {
                // 保存人脸记录
                FaceRecordDO faceRecord = new FaceRecordDO();
                faceRecord.setUserId(userId);
                faceRecord.setFaceToken(result.getJSONObject("result").getStr("face_token"));
                faceRecord.setGroupId(groupId);
                // faceRecord.setImageUrl(java.util.Base64.getEncoder().encodeToString(imageBytes)); // 不再保存Base64编码的图片，避免数据过长
                faceRecord.setFaceInfo(result.toString());
                faceRecord.setEnabled(true);
                faceRecord.setCreateTime(LocalDateTime.now());
                faceRecord.setUpdateTime(LocalDateTime.now());
                
                faceRecordService.createRecord(faceRecord);
            }
            
            return result;
        } catch (Exception e) {
            log.error("人脸注册失败", e);
            createFaceLog(userId, "REGISTER", null, false, e.getMessage(), null);
            throw exception(FACE_REGISTER_FAILED, e.getMessage());
        }
    }

    @Override
    public Map<String, Object> searchFace(MultipartFile faceImage, String groupId) {
        try {
            AipFace client = getAipFaceClient();
            
            // 转换图片为Base64
            byte[] imageBytes = faceImage.getBytes();
            String imageType = "BASE64";
            String image = java.util.Base64.getEncoder().encodeToString(imageBytes);
            
            // 调用百度API搜索人脸
            HashMap<String, Object> options = new HashMap<>();
            options.put("quality_control", "NORMAL");
            options.put("liveness_control", "LOW");
            options.put("user_top_num", "10");
            
            org.json.JSONObject baiduResult = client.search(image, imageType, groupId, options);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 记录日志
            createFaceLog(null, "SEARCH", null, result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), 
                         result.getInt("error_code") == 0 ? result.getJSONObject("result").getDouble("user_list[0].score") : null);
            
            return result;
        } catch (Exception e) {
            log.error("人脸搜索失败", e);
            createFaceLog(null, "SEARCH", null, false, e.getMessage(), null);
            throw exception(FACE_SEARCH_FAILED, e.getMessage());
        }
    }

    @Override
    public Map<String, Object> detectFace(MultipartFile faceImage) {
        try {
            AipFace client = getAipFaceClient();
            
            // 转换图片为Base64
            byte[] imageBytes = faceImage.getBytes();
            String imageType = "BASE64";
            String image = java.util.Base64.getEncoder().encodeToString(imageBytes);
            
            // 调用百度API检测人脸
            HashMap<String, Object> options = new HashMap<>();
            options.put("face_field", "age,beauty,expression,face_shape,gender,glasses,landmark,landmark150,quality,eye_status,emotion,face_type,mask,spoofing");
            options.put("max_face_num", "10");
            options.put("face_type", "LIVE");
            
            org.json.JSONObject baiduResult = client.detect(image, imageType, options);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 记录日志
            createFaceLog(null, "DETECT", null, result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), null);
            
            return result;
        } catch (Exception e) {
            log.error("人脸检测失败", e);
            createFaceLog(null, "DETECT", null, false, e.getMessage(), null);
            throw exception(FACE_DETECT_FAILED, e.getMessage());
        }
    }

    @Override
    public Map<String, Object> verifyFace(Long userId, MultipartFile faceImage) {
        try {
            // 权限验证：确保用户只能验证自己的人脸数据
            Long currentUserId = SecurityFrameworkUtils.getLoginUserId();
            if (currentUserId == null) {
                throw exception(USER_NOT_LOGIN);
            }
            if (!currentUserId.equals(userId)) {
                throw new RuntimeException("无权限验证其他用户的人脸数据");
            }
            
            // 获取用户的人脸图片
            FaceRecordDO faceRecord = faceRecordService.getRecordByUserId(userId);
            if (faceRecord == null) {
                throw new RuntimeException("用户人脸信息不存在");
            }
            
            AipFace client = getAipFaceClient();
            
            // 转换图片为Base64
            byte[] imageBytes = faceImage.getBytes();
            String imageType = "BASE64";
            String image = java.util.Base64.getEncoder().encodeToString(imageBytes);
            
            // 注意：由于不再保存图片数据，此方法可能无法正常工作
            // 如果需要人脸验证功能，建议使用百度API的人脸库搜索功能
            // 或者重新设计存储策略
            String storedImageBase64 = faceRecord.getImageUrl(); // 可能为空，因为不再保存图片数据
            
            // 创建MatchRequest列表
            ArrayList<MatchRequest> requests = new ArrayList<>();
            requests.add(new MatchRequest(image, "BASE64"));
            requests.add(new MatchRequest(storedImageBase64, "BASE64"));
            
            org.json.JSONObject baiduResult = client.match(requests);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 记录日志
            Double score = result.getInt("error_code") == 0 ? result.getJSONObject("result").getDouble("score") : null;
            createFaceLog(userId, "VERIFY", faceRecord.getFaceToken(), result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), score);
            
            return result;
        } catch (Exception e) {
            log.error("人脸验证失败", e);
            createFaceLog(userId, "VERIFY", null, false, e.getMessage(), null);
            throw exception(FACE_VERIFY_FAILED, e.getMessage());
        }
    }

    @Override
    public Map<String, Object> deleteFace(Long userId, String groupId) {
        try {
            // 权限验证：确保用户只能删除自己的人脸数据
            Long currentUserId = SecurityFrameworkUtils.getLoginUserId();
            if (currentUserId == null) {
                throw exception(USER_NOT_LOGIN);
            }
            if (!currentUserId.equals(userId)) {
                throw new RuntimeException("无权限删除其他用户的人脸数据");
            }
            
            AipFace client = getAipFaceClient();
            
            // 调用百度API删除人脸
            HashMap<String, String> options = new HashMap<>();
            org.json.JSONObject baiduResult = client.deleteUser(groupId, userId.toString(), options);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 记录日志
            createFaceLog(userId, "DELETE", null, result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), null);
            
            if (result.getInt("error_code") == 0) {
                // 删除本地人脸记录
                FaceRecordDO faceRecord = faceRecordService.getRecordByUserId(userId);
                if (faceRecord != null) {
                    faceRecordService.deleteRecord(faceRecord.getId());
                }
            }
            
            return result;
        } catch (Exception e) {
            log.error("人脸删除失败", e);
            createFaceLog(userId, "DELETE", null, false, e.getMessage(), null);
            throw exception(FACE_DELETE_FAILED, e.getMessage());
        }
    }

    @Override
    public Boolean deleteFace(FaceDeleteReqVO deleteReqVO) {
        try {
            Map<String, Object> result = deleteFace(deleteReqVO.getUserId(), deleteReqVO.getGroupId());
            JSONObject jsonResult = JSONUtil.parseObj(result);
            return jsonResult.getInt("error_code") == 0;
        } catch (Exception e) {
            log.error("删除人脸失败", e);
            return false;
        }
    }

    // ========== Base64 版本的方法实现 ==========

    @Override
    public FaceOperationRespVO registerFaceBase64(FaceRegisterBase64ReqVO registerReqVO) {
        long startTime = System.currentTimeMillis();
        try {
            // 获取配置
            FaceConfigDO config = faceConfigService.getConfig(registerReqVO.getConfigId());
            if (config == null || !config.getEnabled()) {
                throw exception(FACE_CONFIG_NOT_ENABLED);
            }
            
            AipFace client = new AipFace(config.getAppId(), config.getApiKey(), config.getSecretKey());
            
            // 调用百度API注册人脸
            HashMap<String, String> options = new HashMap<>();
            if (StrUtil.isNotBlank(registerReqVO.getUserInfo())) {
                options.put("user_info", registerReqVO.getUserInfo());
            }
            if (StrUtil.isNotBlank(registerReqVO.getUserName())) {
                options.put("user_info", registerReqVO.getUserName());
            }
            options.put("quality_control", "NORMAL");
            options.put("liveness_control", "LOW");
            
            log.info("开始调用百度API注册人脸，用户ID: {}, 分组ID: {}", registerReqVO.getUserId(), registerReqVO.getGroupId());
            org.json.JSONObject baiduResult = client.addUser(registerReqVO.getImage(), "BASE64", 
                    registerReqVO.getGroupId(), registerReqVO.getUserId(), options);
            JSONObject result = new JSONObject(baiduResult.toString());
            log.info("百度API返回结果: {}", result.toString());
            
            // 记录日志
            createFaceLog(Long.valueOf(registerReqVO.getUserId()), "REGISTER", null, 
                         result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), null);
            
            // 构建响应对象
            FaceOperationRespVO response = new FaceOperationRespVO();
            response.setProcessTime(System.currentTimeMillis() - startTime);
            response.setUserId(registerReqVO.getUserId());
            response.setRawData(result.toString());
            
            if (result.getInt("error_code") == 0) {
                // 保存人脸记录
                FaceRecordDO faceRecord = new FaceRecordDO();
                faceRecord.setUserId(Long.valueOf(registerReqVO.getUserId()));
                String faceToken = result.getJSONObject("result").getStr("face_token");
                faceRecord.setFaceToken(faceToken);
                faceRecord.setGroupId(registerReqVO.getGroupId());
                // 不再保存Base64图片数据，避免数据过长导致数据库问题
                // faceRecord.setImageUrl(registerReqVO.getImage());
                faceRecord.setFaceInfo(result.toString());
                faceRecord.setEnabled(true);
                faceRecord.setCreateTime(LocalDateTime.now());
                faceRecord.setUpdateTime(LocalDateTime.now());
                
                faceRecordService.createRecord(faceRecord);
                log.info("人脸记录保存成功，记录ID: {}", faceRecord.getId());
                
                // 设置成功响应
                response.setSuccess(true);
                response.setFaceToken(faceToken);
            } else {
                // 设置失败响应
                response.setSuccess(false);
                response.setErrorCode(result.getInt("error_code"));
                response.setErrorMessage(result.getStr("error_msg"));
            }
            
            log.info("人脸注册处理完成，成功: {}", response.getSuccess());
            return response;
        } catch (Exception e) {
            log.error("人脸注册失败，用户ID: {}, 错误信息: {}", registerReqVO.getUserId(), e.getMessage(), e);
            createFaceLog(Long.valueOf(registerReqVO.getUserId()), "REGISTER", null, false, e.getMessage(), null);
            
            // 返回错误响应
            FaceOperationRespVO response = new FaceOperationRespVO();
            response.setSuccess(false);
            response.setErrorMessage(e.getMessage());
            response.setProcessTime(System.currentTimeMillis() - startTime);
            response.setUserId(registerReqVO.getUserId());
            return response;
        }
    }

    @Override
    public FaceSearchRespVO searchFaceBase64(FaceSearchBase64ReqVO searchReqVO) {
        long startTime = System.currentTimeMillis();
        try {
            // 获取配置
            FaceConfigDO config = faceConfigService.getConfig(searchReqVO.getConfigId());
            if (config == null || !config.getEnabled()) {
                throw exception(FACE_CONFIG_NOT_ENABLED);
            }
            
            AipFace client = new AipFace(config.getAppId(), config.getApiKey(), config.getSecretKey());
            
            // 调用百度API搜索人脸
            HashMap<String, Object> options = new HashMap<>();
            options.put("quality_control", "NORMAL");
            options.put("liveness_control", "LOW");
            options.put("user_top_num", searchReqVO.getMaxUserNum().toString());
            
            org.json.JSONObject baiduResult = client.search(searchReqVO.getImage(), "BASE64", 
                    searchReqVO.getGroupId(), options);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 构建响应对象
            FaceSearchRespVO response = new FaceSearchRespVO();
            response.setProcessTime(System.currentTimeMillis() - startTime);
            response.setRawData(result.toString());
            
            if (result.getInt("error_code") == 0) {
                // 解析用户列表
                List<FaceSearchRespVO.FaceSearchUserVO> userList = new ArrayList<>();
                JSONObject resultObj = result.getJSONObject("result");
                if (resultObj != null && resultObj.containsKey("user_list")) {
                    JSONArray userArray = resultObj.getJSONArray("user_list");
                    for (int i = 0; i < userArray.size(); i++) {
                        JSONObject userObj = userArray.getJSONObject(i);
                        FaceSearchRespVO.FaceSearchUserVO userVO = new FaceSearchRespVO.FaceSearchUserVO();
                        userVO.setUserId(userObj.getStr("user_id"));
                        userVO.setScore(userObj.getDouble("score"));
                        userVO.setGroupId(userObj.getStr("group_id"));
                        if (userObj.containsKey("face_token")) {
                            userVO.setFaceToken(userObj.getStr("face_token"));
                        }
                        userList.add(userVO);
                    }
                }
                
                response.setSuccess(true);
                response.setUserList(userList);
                
                // 记录日志
                Double topScore = userList.isEmpty() ? null : userList.get(0).getScore();
                createFaceLog(null, "SEARCH", null, true, null, topScore);
            } else {
                // 设置失败响应
                response.setSuccess(false);
                response.setErrorCode(result.getInt("error_code"));
                response.setErrorMessage(result.getStr("error_msg"));
                
                // 记录日志
                createFaceLog(null, "SEARCH", null, false, result.getStr("error_msg"), null);
            }
            
            return response;
        } catch (Exception e) {
            log.error("人脸搜索失败", e);
            createFaceLog(null, "SEARCH", null, false, e.getMessage(), null);
            
            // 返回错误响应
            FaceSearchRespVO response = new FaceSearchRespVO();
            response.setSuccess(false);
            response.setErrorMessage(e.getMessage());
            response.setProcessTime(System.currentTimeMillis() - startTime);
            return response;
        }
    }

    @Override
    public String detectFaceBase64(FaceDetectBase64ReqVO detectReqVO) {
        try {
            // 获取配置
            FaceConfigDO config = faceConfigService.getConfig(detectReqVO.getConfigId());
            if (config == null || !config.getEnabled()) {
                throw exception(FACE_CONFIG_NOT_ENABLED);
            }
            
            AipFace client = new AipFace(config.getAppId(), config.getApiKey(), config.getSecretKey());
            
            // 调用百度API检测人脸
            HashMap<String, Object> options = new HashMap<>();
            if (StrUtil.isNotBlank(detectReqVO.getFaceField())) {
                options.put("face_field", detectReqVO.getFaceField());
            } else {
                options.put("face_field", "age,beauty,expression,face_shape,gender,glasses,landmark,landmark150,quality,eye_status,emotion,face_type,mask,spoofing");
            }
            options.put("max_face_num", "10");
            options.put("face_type", "LIVE");
            
            org.json.JSONObject baiduResult = client.detect(detectReqVO.getImage(), "BASE64", options);
            JSONObject result = new JSONObject(baiduResult.toString());
            
            // 记录日志
            createFaceLog(null, "DETECT", null, result.getInt("error_code") == 0, 
                         result.getInt("error_code") == 0 ? null : result.getStr("error_msg"), null);
            
            return result.toString();
        } catch (Exception e) {
            log.error("人脸检测失败", e);
            createFaceLog(null, "DETECT", null, false, e.getMessage(), null);
            throw exception(FACE_DETECT_FAILED, e.getMessage());
        }
    }

    /**
     * 创建人脸操作日志
     */
    private void createFaceLog(Long userId, String operationType, String faceToken, Boolean success, String errorMessage, Double score) {
        FaceLogDO faceLog = new FaceLogDO();
        faceLog.setUserId(userId);
        faceLog.setOperationType(operationType);
        faceLog.setFaceToken(faceToken);
        faceLog.setScore(score);
        faceLog.setSuccess(success);
        faceLog.setErrorMessage(errorMessage);
        faceLog.setIpAddress(ServletUtils.getClientIP());
        faceLog.setUserAgent(ServletUtils.getUserAgent());
        faceLog.setCreateTime(LocalDateTime.now());
        
        faceLogService.createLog(faceLog);
    }

}